#include "stdlib.hpp"

#include <purewell/directory.hpp>

#if defined(__PW_HAVE_DIRENT_H)
#	include <dirent.h>
#elif defined(__PW_HAVE_SYS_DIRENT_H)
#	include <sys/dirent.h>
#else
// do nothing...
#endif

namespace purewell
{

#if defined(__PW_HAVE_OPENDIR)
enum
{
	_PWDIRENT_SIZE = (sizeof(struct dirent)+NAME_MAX+1),
};

typedef union __pwdirent_t
{
	struct dirent entry;
	char buf[_PWDIRENT_SIZE];
} __pwdirent_t;

typedef struct __pwdir_t
{
	DIR*			dir;
	std::string		path;
} __pwdir_t;
#endif// __PW_HAVE_OPENDIR

#define defdir(x) __pwdir_t* x((__pwdir_t*)m_pData)
#define cdefdir(x) const __pwdir_t* x((const __pwdir_t*)m_pData)

PWDirectory*
PWDirectory::create(const char* path)
{
#if defined(__PW_HAVE_OPENDIR)
	PWDirectory* pdir(new PWDirectory(path));
	if ( NULL == pdir )
	{
		return NULL;
	}

	if ( NULL == pdir->m_pData )
	{
		delete pdir;
		return NULL;
	}

	return pdir;
#else
	__PWERRNO_NOIMPL();
	return NULL;
#endif
}

void
PWDirectory::release(PWDirectory* obj)
{
	delete obj;
}

PWDirectory::PWDirectory(const char* path) : m_pData(NULL)
{
#if defined(__PW_HAVE_OPENDIR)
	__pwdir_t* cont(NULL);
	DIR* pdir(NULL);
	do
	{
		cont = new __pwdir_t;
		if ( NULL == cont )
		{
			break;
		}

		pdir = opendir(path);
		if ( NULL == pdir )
		{
			break;
		}

		cont->dir = pdir;
		cont->path = path;
		m_pData = cont;
		return;
	} while (false);

	if ( NULL != pdir )
	{
		closedir(pdir);
		pdir = NULL;
	}

	if ( NULL != cont )
	{
		delete cont;
		cont = NULL;
	}
#else
	__PWERRNO_NOIMPL();
#endif
}

PWDirectory::~PWDirectory()
{
#if defined(__PW_HAVE_OPENDIR)
	if ( NULL != m_pData )
	{
		defdir(dir);
		if ( NULL != dir->dir )
		{
			closedir(dir->dir);
			dir->dir = NULL;
		}

		delete dir;
		m_pData = NULL;
	}
#else
	__PWERRNO_NOIMPL();
#endif
}

void
PWDirectory::resetPosition(void)
{
#if defined(__PW_HAVE_OPENDIR)
	defdir(ctx);
	DIR* pdir(ctx->dir);

	rewinddir(pdir);
#else
	__PWERRNO_NOIMPL();
#endif
}

bool
PWDirectory::getEntry(bool& done, std::string& name)
{
#if defined(__PW_HAVE_OPENDIR)
	defdir(ctx);
	DIR* pdir(ctx->dir);
	__pwdirent_t tmpent;
	struct dirent* pentry(&(tmpent.entry));
	struct dirent* result(NULL);

	name.clear();

	int _res( readdir_r(pdir, pentry, &result) );
	if ( 0 != _res )
	{
		return false;
	}

	if ( NULL == result )
	{
		done = true;
		return true;
	}

	name = result->d_name;
	done = false;
	return true;
#else
	__PWERRNO_NOIMPL();
	return false;
#endif
}

bool
PWDirectory::getAllEntries(entry_cont& cnt, bool resetpos)
{
#if defined(__PW_HAVE_OPENDIR)
	defdir(ctx);
	DIR* pdir(ctx->dir);
	__pwdirent_t tmpent;
	struct dirent* pentry(&(tmpent.entry));
	struct dirent* result(NULL);

	cnt.clear();

	if ( true == resetpos )
	{
		rewinddir(pdir);
	}

	while ( 0 == readdir_r(pdir, pentry, &result))
	{
		if ( NULL == result )
		{
			return true;
		}

		cnt.push_back(result->d_name);
	}

	return true;
#else
	__PWERRNO_NOIMPL();
	return false;
#endif
}

};

